﻿using System;
using System.Linq;

namespace ReactiveGraph.Core
{
    public class Property<T> : IProperty
    {
        private readonly string _name;
        private IObserver<NodeEvent> _changed = Observer.Create<NodeEvent>(e => { });
        private IReactiveNode _conceptualParent;
        private T _value;

        public Property(string name)
        {
            _name = name;
        }

        public virtual T Value
        {
            get { return _value; }
            set
            {
                if (Equals(value, _value)) return;
                _value = value;
                OnPropertyChanged(value);
            }
        }

        #region IProperty Members

        void IProperty.Initialize(IReactiveNode conceptualParent, IObserver<NodeEvent> changed)
        {
            _changed = changed;
            _conceptualParent = conceptualParent;
        }

        Type IProperty.Type
        {
            get { return typeof (T); }
        }

        string IProperty.Name
        {
            get { return _name; }
        }

        object IProperty.Value
        {
            get { return Value; }
            set { Value = (T) value; }
        }

        #endregion

        public IObservable<T> PropertyChanged()
        {
            if (_conceptualParent == null) return Observable.Empty<T>();
            return _conceptualParent.Events
                .Where(e => e.Type == EventType.PropertyChange && e.Source.Property == this)
                .Select(e => e.Source.PropertyTriggerValue)
                .Cast<T>();
        }

        protected void OnPropertyChanged(T value)
        {
            _changed.OnNext(NodeEvent.PropertyChanged(_conceptualParent, this, value));
        }
    }
}